using LuaFramework;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XLua;

namespace UIFramework
{
    /// <summary>
    /// UI框架管理类
    /// </summary>
    public class UIManager : MonoBehaviour
    {
        /// <summary>
        /// 画布
        /// </summary>
        public GameObject _MainCanvas;
        #region UIManager类的单例
        private static UIManager _instance;
        private UIManager() { }
        public static UIManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = GameInit.GameManager.AddComponent<UIManager>();
                }
                return _instance;
            }
        }
        #endregion

        /// <summary>
        /// 所有的通过UI管理器缓存起来的窗体
        /// </summary>
        public Dictionary<string, BaseUIView> _DicAllFormCache = new Dictionary<string, BaseUIView>();
        /// <summary>
        /// 正在显示的UI窗体的集合，不包括反向切换的窗体
        /// </summary>
        public Dictionary<string, BaseUIView> _DicShowingFormCache = new Dictionary<string, BaseUIView>();
        /// <summary>
        /// 仅存具有反向切换功能的UI窗体的缓存集合
        /// </summary>
        public Stack<BaseUIView> _StackReverseCache = new Stack<BaseUIView>();

        private Dictionary<string, GameObject> _NodeList;       //该游戏对象的字节点
        public Transform _UIRootNode;                           //UI根节点 MainCanvas
        private Transform _NodeTopest;                         //最顶部挂载节点
        private Transform _NodeBottom;                         //最底部挂载节点
        public Transform _NodeNormal;                          //普通UI挂载节点
        public Transform _NodeFixed;                           //固定UI挂载节点
        public Transform _NodePopUp;                           //弹窗UI窗口挂载节点
        public Transform _NodeTips;                            //提示信息UI挂载节点

        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            _MainCanvas = GameObject.FindGameObjectWithTag("MainCanvas");
            DontDestroyOnLoad(_MainCanvas);
            _MainCanvas.GetComponent<Image>().enabled = false;

            _NodeList = _MainCanvas.GetComponent<UINameTable>().GORefrence;

            _UIRootNode = _MainCanvas.transform;
            _NodeTopest = _NodeList["Topest"].transform;
            _NodeBottom = _NodeList["Bottom"].transform;
            _NodeNormal = _NodeList["Normal"].transform;
            _NodeFixed = _NodeList["Fixed"].transform;
            _NodePopUp = _NodeList["PopUp"].transform;
            _NodeTips = _NodeList["Tips"].transform;

            //Debug.Log("UIManager Already Init!"); 
        }
        /// <summary>
        /// 切换场景关闭需要关闭的UI窗体
        /// </summary>
        public void ChangeSceneCloseUI()
        {
            foreach (var form in _DicAllFormCache.Values)
            {
                if (form._ChangeSceneClose)
                {
                    SetActiveAndPlayAnim(form, ActiveMode.Close, false);
                }
            }
            //下载面板单独处理
            GameObject go = HotUpdateManager.Instance._UpdatePanel;
            if (go != null && go.activeSelf)
            {
                go.SetActive(false);
            }
        }
        /// <summary>
        /// 得到某一个UI面板的BaseUIView（先加载并实例化）,提供给外部调用
        /// </summary>
        /// <param name="name">面板相对路径名字</param>
        /// <param name="is_cache">是否缓存</param>
        /// <returns></returns>
        public BaseUIView InitAndGetPanel(string name)
        {
            BaseUIView baseui;
            //将要加载的UI面板的名字
            string ui_name = name.Split('/')[name.Split('/').Length - 1];

            //如果已经加载过该窗口则直接返回
            if (_DicAllFormCache.ContainsKey(ui_name))
            {
                baseui = _DicAllFormCache[ui_name];
            }
            //加载窗口并实例化
            else
            {
                GameObject go = Instantiate(LoadAssetManager.Instance.LoadPrefab(name));
                go.name = go.name.Replace("(Clone)", "");
                go.SetActive(false);
                baseui = go.AddComponent<BaseUIView>();

                //缓存UI面板到所有缓存列表去
                //if (baseui._CloseMode == UICloseMode.Hide)
                //{
                _DicAllFormCache.Add(ui_name, baseui);
                //}
                //设置父节点
                SetPanelParent(baseui, go);
                //添加CanvasGroup组件,对UI做动画时需要
                go.AddComponent<CanvasGroup>();
                //添加生命周期映射
                if (go.GetComponent<MapLifeCycle>() == null)
                {
                    go.AddComponent<MapLifeCycle>();
                }
            }

            return baseui;
        }

        /// <summary>
        /// 设置UI的父节点
        /// </summary>
        /// <param name="baseui"></param>
        /// <param name="go"></param>
        private void SetPanelParent(BaseUIView baseui, GameObject go)
        {
            switch (baseui._FormType)
            {
                case UIFormType.Normal: go.transform.SetParent(_NodeNormal, false); break;
                case UIFormType.Fixed: go.transform.SetParent(_NodeFixed, false); break;
                case UIFormType.Tips: go.transform.SetParent(_NodeTips, false); break;
                case UIFormType.PopUp:
                case UIFormType.Reverse: go.transform.SetParent(_NodePopUp, false); break;
            }
        }

        /// <summary>
        /// 直接隐藏或者销毁面板，不播放动画
        /// </summary>
        private void HideOrDestoryPanel(BaseUIView ui_item)
        {
            //当该_NotCloseByOther==true表明他不会被其他窗体打开时影响
            if (ui_item._NotCloseByOther) return;
            //隐藏或销毁
            if (ui_item._CloseMode == UICloseMode.Destroy)
            {
                Destroy(ui_item.gameObject);
            }
            else
            {
                ui_item.gameObject.SetActive(false);
            }
        }

        /// <summary>
        /// 显示UI窗口
        /// </summary>
        /// <param name="baseui"></param>
        public void ShowPanel(BaseUIView baseui)
        {
            //打开过的界面
            baseui._IsLoadAndShow = true;
            //根据打开类型判定关闭其他打开的面板
            if (baseui._OpenAndCloseOther)
            {
                //反向切换UI栈集合
                foreach (var ui_item in _StackReverseCache)
                {
                    HideOrDestoryPanel(ui_item);
                }
                //普通的正在显示的集合
                foreach (var ui_item in _DicShowingFormCache.Values)
                {
                    HideOrDestoryPanel(ui_item);
                }
                //如果关闭该窗口不做处理(关闭时不恢复其他被关闭的窗体的显示状态)则清理掉其他在显示列表的引用
                if (baseui._COUICloseWillDo == CloseOtherUICloseWillDo.DoNothing)
                {
                    _StackReverseCache.Clear();
                    _DicShowingFormCache.Clear();
                }
            }

            //加入正在显示的UI面板的集合
            switch (baseui._FormType)
            {
                case UIFormType.Normal:
                case UIFormType.PopUp:
                case UIFormType.Fixed:
                case UIFormType.Tips:
                    //如果存在该UI窗体这不添加。
                    if (!_DicShowingFormCache.ContainsValue(baseui))
                    {
                        _DicShowingFormCache.Add(baseui.name, baseui);
                    }
                    break;
                case UIFormType.Reverse:
                    //如果有其他的反向面板则先关闭
                    if (_StackReverseCache.Count > 0)
                    {
                        BaseUIView top = _StackReverseCache.Peek();
                        SetActiveAndPlayAnim(top, ActiveMode.Close);
                    }
                    //如果存在该UI窗体这不添加。
                    if (!_StackReverseCache.Contains(baseui))
                    {
                        _StackReverseCache.Push(baseui);
                    }
                    break;
            }

            //激活UI窗体并播放打开动画
            SetActiveAndPlayAnim(baseui, ActiveMode.Open);
            //打印所有UI窗体缓存名字的集合
            //PrintAllUICacheList();
        }

        /// <summary>
        /// 显示、隐藏面板并且播放动画
        /// </summary>
        /// <param name="baseui">被操作的UIForm组件</param>
        /// <param name="open">true显示面板 false关闭面板</param>
        /// <param name="playAnim">是否播放动画</param>
        /// <param name="callback">动画完成播放回调</param>
        /// <param name="speed">动画速度</param>
        private void SetActiveAndPlayAnim(BaseUIView baseui, ActiveMode mode, bool playAnim = true, DTAnimSpeed speed = DTAnimSpeed.Normal, Action callback = null)
        {
            //实际操作的Transform是Content而不是打开面板的根节点
            Transform real_op_trans = baseui.transform.Find("Content");
            //显示面板
            if (mode == ActiveMode.Open)
            {
                baseui.SetMaskAndCheckParam();
                baseui.gameObject.SetActive(true);
                baseui.transform.SetAsLastSibling();
                //不播放动画则直接返回
                if (!playAnim)
                {
                    callback?.Invoke();
                    return;
                }
                //入场动画类型
                DTAnimEffect type = baseui._AnimIn;
                switch (type)
                {
                    case DTAnimEffect.FadeIn:
                        DTAnimManager.Instance.FadeIn(baseui.GetComponent<CanvasGroup>(), callback, speed);
                        break;
                    case DTAnimEffect.ScaleIn:
                        DTAnimManager.Instance.ScaleIn(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.UpIn:
                        DTAnimManager.Instance.FromUpIn(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.DownIn:
                        DTAnimManager.Instance.FromDownIn(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.LeftIn:
                        DTAnimManager.Instance.FromLeftIn(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.RightIn:
                        DTAnimManager.Instance.FromRightIn(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.RotateYIn:
                        DTAnimManager.Instance.RotateYIn(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.RotateZIn:
                        DTAnimManager.Instance.RotateZIn(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.ScaleXIn:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.In, ScaleAxis.X, callback, speed);
                        break;
                    case DTAnimEffect.ScaleX_End_In:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.In, ScaleAxis.X_End, callback, speed);
                        break;
                    case DTAnimEffect.ScaleX_Start_In:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.In, ScaleAxis.X_Start, callback, speed);
                        break;
                    case DTAnimEffect.ScaleYIn:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.In, ScaleAxis.Y, callback, speed);
                        break;
                    case DTAnimEffect.ScaleY_End_In:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.In, ScaleAxis.Y_End, callback, speed);
                        break;
                    case DTAnimEffect.ScaleY_Start_In:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.In, ScaleAxis.Y_Start, callback, speed);
                        break;
                    default:
                        callback?.Invoke();
                        break;
                }

            }
            //关闭面板
            else
            {
                //设置默认关闭面板后执行的回调方法
                if (callback == null)
                {
                    callback = () =>
                    {
                        if (baseui._CloseMode == UICloseMode.Destroy)
                        {
                            if (_DicAllFormCache.ContainsValue(baseui))
                            {
                                foreach (var key in _DicAllFormCache.Keys)
                                {
                                    if (_DicAllFormCache[key] == baseui)
                                    {
                                        _DicAllFormCache.Remove(key);
                                        break;
                                    }
                                }
                            }
                            Destroy(baseui.gameObject);
                        }
                        else
                        {
                            baseui.gameObject.SetActive(false);
                        }
                    };
                }
                //离场动画类型
                DTAnimEffect type = baseui._AnimOut;
                //不播放动画则直接返回
                if (!playAnim)
                {
                    callback.Invoke();
                    return;
                }
                //播放对应的离场动画
                switch (type)
                {
                    case DTAnimEffect.FadeOut:
                        DTAnimManager.Instance.FadeOut(baseui.GetComponent<CanvasGroup>(), callback, speed);
                        break;
                    case DTAnimEffect.ScaleOut:
                        DTAnimManager.Instance.ScaleOut(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.UpOut:
                        DTAnimManager.Instance.FromUpOut(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.DownOut:
                        DTAnimManager.Instance.FromDownOut(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.LeftOut:
                        DTAnimManager.Instance.FromLeftOut(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.RightOut:
                        DTAnimManager.Instance.FromRightOut(real_op_trans, callback, speed);
                        break;
                    case DTAnimEffect.ScaleXOut:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.Out, ScaleAxis.X, callback, speed);
                        break;
                    case DTAnimEffect.ScaleX_End_Out:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.Out, ScaleAxis.X_End, callback, speed);
                        break;
                    case DTAnimEffect.ScaleX_Start_Out:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.Out, ScaleAxis.X_Start, callback, speed);
                        break;
                    case DTAnimEffect.ScaleYOut:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.Out, ScaleAxis.Y, callback, speed);
                        break;
                    case DTAnimEffect.ScaleY_End_Out:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.Out, ScaleAxis.Y_End, callback, speed);
                        break;
                    case DTAnimEffect.ScaleY_Start_Out:
                        DTAnimManager.Instance.ScaleSingleAxis(real_op_trans, InOrOut.Out, ScaleAxis.Y_Start, callback, speed);
                        break;
                    default:
                        callback?.Invoke();
                        break;
                }
            }
        }

        /// <summary>
        /// 关闭UI窗口，C#调用
        /// </summary>
        /// <param name="baseui"></param>
        public void ClosePanelInner(BaseUIView baseui)
        {
            ClosePanel("", baseui);
        }

        /// <summary>
        /// 关闭UI窗口 Lua调用
        /// </summary>
        /// <param name="path_name">关闭UI的相对预制体路径</param>
        public void ClosePanel(string path_name, BaseUIView baseui)
        {
            if (baseui == null)
            {
                baseui = InitAndGetPanel(path_name);
            }

            //播放关闭动画
            SetActiveAndPlayAnim(baseui, ActiveMode.Close);

            switch (baseui._FormType)
            {
                case UIFormType.Normal:
                case UIFormType.PopUp:
                case UIFormType.Fixed:
                    _DicShowingFormCache.Remove(baseui.name);
                    break;
                case UIFormType.Reverse:
                    _StackReverseCache.Pop();
                    //关掉当前反向切换窗口并移除，打开最靠顶的窗口
                    if (_StackReverseCache.Count > 0)
                    {
                        BaseUIView top_baseui = _StackReverseCache.Peek();
                        Debug.Log("反向显示:" + top_baseui.name);
                        SetActiveAndPlayAnim(top_baseui, ActiveMode.Open);
                    }
                    break;
            }
            //关闭时显示之前被当前窗口打开时关闭的窗口
            if (baseui._COUICloseWillDo == CloseOtherUICloseWillDo.ReShowOther && baseui._OpenAndCloseOther)
            {
                //恢复之前的所有被关闭的窗体-正在显示列表的窗体
                foreach (var item in _DicShowingFormCache.Values)
                {
                    SetActiveAndPlayAnim(item, ActiveMode.Open);
                }
                //恢复之前的所有被关闭的窗体-反向切换列表的窗体
                if (_StackReverseCache.Count > 0)
                {
                    BaseUIView top_baseui = _StackReverseCache.Peek();
                    SetActiveAndPlayAnim(top_baseui, ActiveMode.Open);
                }
            }

            //打印所有UI窗体缓存名字的集合
            //PrintAllUICacheList();
        }

        /// <summary>
        /// 打印所有UI窗体缓存名字的集合
        /// </summary>
        public void PrintAllUICacheList()
        {
            string str = "$$所有的UI窗体显示状态列表及被缓存列表\n1.反向切换列表:";
            foreach (var item in _StackReverseCache)
            {
                str += "\n" + item.gameObject.name;
            }
            str += "\n\n2.正在显示的列表:";
            foreach (var item in _DicShowingFormCache.Values)
            {
                str += "\n" + item.gameObject.name;
            }
            str += "\n\n3.所有被缓存的列表:";
            foreach (var item in _DicAllFormCache.Values)
            {
                str += "\n" + item.gameObject.name;
            }
            Debug.Log(str + "\n");
        }
    }
}